package com.iwuyc.tools.commons.util.collection;

import com.iwuyc.tools.commons.structs.collections.ConcurrentHashSet;
import com.iwuyc.tools.commons.util.ObjectUtils;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class Sets {

    /**
     * 将数组转换为并发的set
     *
     * @param elements 元素集合
     * @param <T>      泛型
     * @return 并发的set
     */
    @SafeVarargs
    public static <T> Set<T> asConcurrentSet(T... elements) {
        return asConcurrentSet(asSet(elements));
    }

    /**
     * 将数组转换为并发的set
     *
     * @param elements 元素集合
     * @param <T>      泛型
     * @return 并发的set
     */
    public static <T> Set<T> asConcurrentSet(Collection<T> elements) {
        if (CollectionUtil.isEmpty(elements)) {
            return new ConcurrentHashSet<>();
        }
        final ConcurrentHashSet<T> result = new ConcurrentHashSet<>(elements.size());
        result.addAll(elements);
        return result;
    }
    /**
     * 将数组转为Set
     *
     * @param elements 数组
     * @param <T>      泛型
     * @return Set
     */
    @SafeVarargs
    @SuppressWarnings("varargs")
    public static <T> Set<T> asSet(T... elements) {
        if (ArrayUtil.isEmpty(elements)) {
            return Collections.emptySet();
        }
        HashSet<T> result = new HashSet<>(elements.length);
        Collections.addAll(result, elements);
        return result;
    }

    /**
     * 返回一个不可修改的Set
     *
     * @param elements 元素列表
     * @param <T>      泛型
     * @return 不可修改的Set
     */
    @SafeVarargs
    public static <T> Set<T> unmodifiableSet(T... elements) {
        return unmodifiableSet(asSet(elements));
    }

    /**
     * 返回一个不可修改的Set
     *
     * @param elements 元素列表
     * @param <T>      泛型
     * @return 不可修改的Set
     */
    public static <T> Set<T> unmodifiableSet(Set<T> elements) {
        return Collections.unmodifiableSet(elements);
    }

    /**
     * 合并两个Set, 返回合并后的Set
     *
     * @param one      集合
     * @param otherOne 另一个集合
     * @param <T>      泛型
     * @return 合并后的 Set
     */
    public static <T> Set<T> merge(Set<T> one, Set<T> otherOne) {
        int oneSize = CollectionUtil.sizeOf(one);
        int otherOneSize = CollectionUtil.sizeOf(otherOne);
        final Set<T> result = new HashSet<>(oneSize + otherOneSize);
        result.addAll(ObjectUtils.nullOrDefault(one, Collections.emptySet()));
        result.addAll(ObjectUtils.nullOrDefault(otherOne, Collections.emptySet()));
        return result;
    }

    /**
     * 讲集合中的元素移除指定的元素，返回一个新的集合，不会修改原集合
     *
     * @param sourceSet    原集合
     * @param shouldRemove 需要移除的元素
     * @param <T>          泛型
     * @return 移除了指定元素的集合
     */
    public static <T> Set<T> removeAll(Set<T> sourceSet, Collection<T> shouldRemove) {
        if (CollectionUtil.isEmpty(sourceSet)) {
            return Collections.emptySet();
        }
        final Set<T> result = new HashSet<>(sourceSet);
        if (CollectionUtil.isEmpty(shouldRemove)) {
            return result;
        }
        result.removeAll(shouldRemove);
        return result;
    }

    /**
     * 讲集合中的元素移除指定的元素，返回一个新的集合，不会修改原集合
     *
     * @param sourceSet    原集合
     * @param shouldRemove 需要移除的元素
     * @param <T>          泛型
     * @return 移除了指定元素的集合
     */
    public static <T> Set<T> removeAll(Set<T> sourceSet, T... shouldRemove) {
        return removeAll(sourceSet, asSet(shouldRemove));
    }

    /**
     * 判断源集合是否包含所有指定的元素
     *
     * @param sourceSet        源集合
     * @param containsElements 需要判断的元素
     * @param <T>              泛型
     * @return 是否包含所有指定的元素
     */
    public static <T> boolean containsAll(Set<T> sourceSet, Collection<T> containsElements) {
        int sourceSetSize = CollectionUtil.sizeOf(sourceSet);
        int containsElementsSize = CollectionUtil.sizeOf(containsElements);
        if (containsElementsSize > sourceSetSize || sourceSetSize == 0) {
            return false;
        }
        if (containsElementsSize == 0) {
            return true;
        }
        for (T item : containsElements) {
            if (!sourceSet.contains(item)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判断源集合是否包含所有指定的元素
     *
     * @param sourceSet        源集合
     * @param containsElements 需要判断的元素
     * @param <T>              泛型
     * @return 是否包含所有指定的元素
     */
    @SafeVarargs
    public static <T> boolean containsAll(Set<T> sourceSet, T... containsElements) {
        return containsAll(sourceSet, asSet(containsElements));
    }
}
